package xyz.xtt.asset.service.impl;

import static xyz.xtt.common.asset.AssertUtils.isFalse;
import static xyz.xtt.common.asset.AssertUtils.isNull;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import org.apache.kafka.common.errors.IllegalSaslStateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.primitives.Longs;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.asset.api.enums.ReferProtocolEnum;
import xyz.xtt.asset.api.enums.SellPatternEnum;
import xyz.xtt.asset.api.enums.StatusAllEnum;
import xyz.xtt.asset.client.response.AssetAccountResponse;
import xyz.xtt.asset.constants.ErrorMessage;
import xyz.xtt.asset.entity.TblAssetAccount;
import xyz.xtt.asset.entity.TblAssetTransaction;
import xyz.xtt.asset.entity.TblAssetTransactionRecord;
import xyz.xtt.asset.enums.AccountStateEnum;
import xyz.xtt.asset.enums.OrderTypeEnum;
import xyz.xtt.asset.enums.TransactionSideEnum;
import xyz.xtt.asset.mapper.TblAssetAccountMapper;
import xyz.xtt.asset.request.OperateUpRequest;
import xyz.xtt.asset.service.ITblAssetAccountService;
import xyz.xtt.asset.service.ITblAssetNoService;
import xyz.xtt.asset.service.ITblAssetTransactionRecordService;
import xyz.xtt.asset.service.ITblAssetTransactionService;
import xyz.xtt.asset.utils.BigDecimalUtils;
import xyz.xtt.common.asset.AssertUtils;

/**
 * <p>
 * 1155资产关系表 服务实现类
 * </p>
 *
 * @author author
 * @since 2024-12-25
 */
@RefreshScope
@Slf4j
@Service
public class TblAssetAccountServiceImpl extends ServiceImpl<TblAssetAccountMapper, TblAssetAccount> implements ITblAssetAccountService {
	private static final String FOR_UPDATE = "for update";
	@Autowired
	private ITblAssetTransactionRecordService iTblAssetTransactionRecordService;
	@Autowired
	private ITblAssetTransactionService iTblAssetTransactionService;
	@Value("${activity.everyday.assetId}")
	private Long everydayAssetId;
	@Autowired
	private ITblAssetNoService iTblAssetNoService;

	@Override
	public Long ownNum(Long assetId, Long userId) {
		Long num = JoinWrappers
				.lambda(TblAssetAccount.class)
				.selectSum(TblAssetAccount::getAmount)
				.eq(TblAssetAccount::getAssetId, assetId)
				.eq(TblAssetAccount::getOwnerId, userId)
				.one(Long.class);
		return Objects.isNull(num) ? 0L : num;
	}

	@Override
	public List<TblAssetAccount> ownerList(Long assetId, Long userId) {
		LambdaQueryChainWrapper<TblAssetAccount> query = new LambdaQueryChainWrapper<>(baseMapper);
		query.eq(TblAssetAccount::getAssetId, assetId).eq(TblAssetAccount::getOwnerId, userId).orderByDesc(TblAssetAccount::getCreateTime);
		List<TblAssetAccount> list = query.list();
		return list;
	}

	@Override
	public TblAssetAccount ownerAssetForUpdate(Long assetId, Long userId) {
		LambdaQueryChainWrapper<TblAssetAccount> query = new LambdaQueryChainWrapper<>(baseMapper);
		query.eq(TblAssetAccount::getAssetId, assetId).eq(TblAssetAccount::getOwnerId, userId).last(FOR_UPDATE);
		return query.one();
	}

	@Override
	public TblAssetAccount ownerAssetForUpdate(Long accountNo) {
		LambdaQueryChainWrapper<TblAssetAccount> query = new LambdaQueryChainWrapper<>(baseMapper);
		query.eq(TblAssetAccount::getAccountNo, accountNo).last(FOR_UPDATE);
		return query.one();
	}

	@Override
	public TblAssetAccount account(Long assetId, Long userId) {
		LambdaQueryChainWrapper<TblAssetAccount> query = new LambdaQueryChainWrapper<>(baseMapper);
		query.eq(TblAssetAccount::getAssetId, assetId).gt(TblAssetAccount::getAmount, 0).eq(TblAssetAccount::getOwnerId, userId);
		return query.one();
	}

	@Override
	public TblAssetAccount accountNoCheckAmount(Long assetId, Long userId) {
		LambdaQueryChainWrapper<TblAssetAccount> query = new LambdaQueryChainWrapper<>(baseMapper);
		query.eq(TblAssetAccount::getAssetId, assetId).eq(TblAssetAccount::getOwnerId, userId);
		return query.one();
	}

	@Override
	public TblAssetAccount accountInfo(Long accountNo) {
		LambdaQueryChainWrapper<TblAssetAccount> query = new LambdaQueryChainWrapper<>(baseMapper);
		query.eq(TblAssetAccount::getAccountNo, accountNo);
		return query.one();
	}

	@Override
	public TblAssetAccount accountIsNullCreate(Long assetId, Long userId, BigDecimal price) {
		LambdaQueryChainWrapper<TblAssetAccount> query = new LambdaQueryChainWrapper<>(baseMapper);
		query.eq(TblAssetAccount::getAssetId, assetId).eq(TblAssetAccount::getOwnerId, userId);
		return query.oneOpt().orElse(initAccount(assetId, userId, ReferProtocolEnum.ERC_1155, price));
	}

	@Override
	public TblAssetAccount accountIsNullCreateAfterInit(Long assetId, Long userId) {
		LambdaQueryChainWrapper<TblAssetAccount> query = new LambdaQueryChainWrapper<>(baseMapper);
		query.eq(TblAssetAccount::getAssetId, assetId).eq(TblAssetAccount::getOwnerId, userId);
		return query.oneOpt().orElse(initAccountOneAmount(assetId, userId, ReferProtocolEnum.ERC_7211, BigDecimal.ONE, BigDecimal.ZERO));
	}

	@Override
	public void move(List<TblAssetAccount> ownerList, Long transactionId, Long from, Long to, Integer num) {
		int surplus = num;
		HashMap<Long, BigDecimal> minusNumMap = Maps.newHashMap();
		HashMap<Long, TblAssetAccount> plusNumMap = Maps.newHashMap();
		for (TblAssetAccount trb : ownerList) {
			BigDecimal amount = trb.getAmount();
			int itemNum = amount.intValue();
			surplus -= itemNum;
			// 大于0说明不够减，要继续
			if (surplus > 0) {
				minusNumMap.put(trb.getId(), amount);
			} else if (surplus == 0) {
				minusNumMap.put(trb.getId(), amount);
				break;
			} else if (surplus < 0) {
				// 说明足够了
				minusNumMap.put(trb.getId(), new BigDecimal(String.valueOf(itemNum - Math.abs(surplus))));
				break;
			}
			plusNumMap.put(trb.getId(), trb);
		}
		List<TblAssetAccount> targetList = Lists.newArrayList();
		minusNumMap.forEach((k, v) -> {
			LambdaUpdateChainWrapper<TblAssetAccount> updateWrapper = new LambdaUpdateChainWrapper<>(baseMapper);
			TblAssetAccount tblAssetTransactionRelation = plusNumMap.get(k);
			updateWrapper.eq(TblAssetAccount::getId, k).set(TblAssetAccount::getAmount, tblAssetTransactionRelation.getAmount().subtract(v));
			TblAssetAccount build = tblAssetTransactionRelation.buildOther(tblAssetTransactionRelation.getAccountNo(), transactionId, to, v);
			targetList.add(build);
		});
		if (CollectionUtil.isNotEmpty(targetList)) {
			this.saveBatch(targetList);
		}
	}

	// 帐户操作
	@Override
	public TblAssetTransactionRecord accountOpertor(TblAssetTransaction buildTransaction, TblAssetAccount assetAccount, TransactionSideEnum side) {
		AssertUtils.isTrue(assetAccount.isLock(), ErrorMessage.ACCOUNT_LOCK, () -> log.info("account: {} is lock", assetAccount.getAccountNo()));
		BigDecimal price = buildTransaction.getPrice();
		// 如果没传价格，取0
		if (Objects.isNull(price)) {
			price = BigDecimal.ZERO;
		}
		// 如果是负数，取0
		if (!BigDecimalUtils.isGreaterThanZero(price)) {
			price = BigDecimal.ZERO;
		}
		BigDecimal totalPrice = buildTransaction.getAmount().multiply(price);
		BigDecimal after = BigDecimal.ZERO;
		BigDecimal sellAmount = BigDecimal.ZERO;
		if (Objects.equals(side, TransactionSideEnum.BUY)) {
			// 加法
			after = assetAccount.getAmount().add(buildTransaction.getAmount());
		} else if (Objects.equals(side, TransactionSideEnum.SELL)) {
			// 减法
			after = assetAccount.getAmount().subtract(buildTransaction.getAmount());
			if (assetAccount.getSellAmount() != null) {
				sellAmount = assetAccount.getSellAmount().subtract(buildTransaction.getAmount());
				if (buildTransaction.isPay()) {
					AssertUtils.isTrue(BigDecimal.ZERO.compareTo(sellAmount) > 0, ErrorMessage.INSUFFICIENT_BALANCE);
				}
				sellAmount = BigDecimal.ZERO.compareTo(sellAmount) > 0 ? BigDecimal.ZERO : sellAmount;
			}
//			isTrue(assetAccount.getSellAmount() != null
//					&& assetAccount.getSellAmount().compareTo(BigDecimal.ZERO) != 0
//					&& assetAccount.getSellAmount().compareTo(buildTransaction.getAmount()) < 0,ErrorMessage.UNKNOWN_ERROR);
//			sellAmount =  assetAccount.getSellAmount().subtract(buildTransaction.getAmount());
		} else {
			AssertUtils.isTrue(true, ErrorMessage.UNKNOWN_ERROR);
		}
		// 如果是负数，说明余量不足
		AssertUtils.isTrue(BigDecimal.ZERO.compareTo(after) > 0, ErrorMessage.INSUFFICIENT_BALANCE);
		LambdaUpdateChainWrapper<TblAssetAccount> updateWrapper = new LambdaUpdateChainWrapper<>(baseMapper);

		updateWrapper
				.eq(TblAssetAccount::getId, assetAccount.getId())
				.eq(TblAssetAccount::getVer, assetAccount.getVer())
				.set(TblAssetAccount::getUpdateTime, LocalDateTime.now())
				.setIncrBy(TblAssetAccount::getVer, 1)
				.set(Objects.equals(side, TransactionSideEnum.SELL), TblAssetAccount::getSellAmount, sellAmount)
				.set(TblAssetAccount::getAmount, after);
		boolean update = updateWrapper.update();
		if (update) {
			// 记帐
			return TblAssetTransactionRecord
					.builder()
					.id(IdUtil.getSnowflakeNextId())
					.side(side.code())
					.accountNo(assetAccount.getAccountNo())
					.beforeAmount(assetAccount.getAmount())
					.transactionId(buildTransaction.getOrderId())
					.totalPrice(totalPrice)
					.amount(buildTransaction.getAmount())
					.fees(BigDecimal.ZERO)
					.afterAmount(after)
					.createTime(LocalDateTime.now())
					.build();
		}
		throw new IllegalSaslStateException("update account blance exception");
	}

	/**
	 * 增加方
	 * 
	 * 如果帐帐户不存在，就初始化
	 * 
	 */
	@Override
	public TblAssetTransactionRecord plus(TblAssetTransaction buildTransaction, ReferProtocolEnum referProtocol) {
		return plus(buildTransaction, referProtocol, StatusAllEnum.YES.code());
	}

	@Override
	public TblAssetTransactionRecord plus(TblAssetTransaction buildTransaction, ReferProtocolEnum referProtocol, Integer visiable) {
		AssertUtils.isNull(referProtocol, ErrorMessage.UNSUPPORTED_REFER_PROTOCOL, () -> log.info("Unsupported referProtocol types"));
		Long buyerUserId = Longs.tryParse(buildTransaction.getBuyerUserId());
		TblAssetAccount ownerAsset = ownerAssetForUpdate(buildTransaction.getAssetId(), buyerUserId);

		if (Objects.isNull(ownerAsset)) {
			TblAssetAccount account = initAccount(buildTransaction.getAssetId(), buyerUserId, referProtocol, buildTransaction.getPrice(), visiable);
			AssertUtils.isNull(account, ErrorMessage.ASSET_NOT_EXIST, () -> log.info("plus account is null"));
			return accountOpertor(buildTransaction, account, TransactionSideEnum.BUY);
		} else {
			return accountOpertor(buildTransaction, ownerAsset, TransactionSideEnum.BUY);
		}
	}

	@Override
	public TblAssetAccount initAccount(Long assetId, Long userId, ReferProtocolEnum referProtocol, BigDecimal price) {
		return initAccount(assetId, userId, referProtocol, price, StatusAllEnum.YES.code());
	}

	@Override
	public TblAssetAccount initAccount(Long assetId, Long userId, ReferProtocolEnum referProtocol, BigDecimal price, Integer visible) {
		return initAccountOneAmount(assetId, userId, referProtocol, BigDecimal.ZERO, price, visible);
	}

	@Override
	public TblAssetAccount initAccountOneAmount(Long assetId, Long userId, ReferProtocolEnum referProtocol, BigDecimal amount, BigDecimal price) {
		return initAccountOneAmount(assetId, userId, referProtocol, amount, price, StatusAllEnum.YES.code());
	}

	@Override
	public TblAssetAccount initAccountOneAmount(Long assetId, Long userId, ReferProtocolEnum referProtocol, BigDecimal amount, BigDecimal price,
			Integer visible) {
		TblAssetAccount assetAccount = TblAssetAccount
				.builder()
				.id(IdUtil.getSnowflakeNextId())
				.accountNo(IdUtil.getSnowflakeNextId())
				.assetId(assetId)
				.ownerId(userId)
				.amount(amount)
				.state(AccountStateEnum.NORMAL.code())
				.updateTime(LocalDateTime.now())
				.createTime(LocalDateTime.now())
				.visiable(visible)
				.price(price)
				.ver(0L)
				.referProtocol(referProtocol.getCode())
				.build();
		if (BigDecimalUtils.isGreater(amount)) {
			assetAccount.setVer(1L);
		}
		Boolean init = this.save(assetAccount);
		if (init) {
			return assetAccount;
		}
		return null;
	}

	/**
	 * 减少方
	 * 
	 * 减少方的帐户必须存在
	 */
	@Override
	public TblAssetTransactionRecord minus(TblAssetTransaction buildTransaction, ReferProtocolEnum referProtocol) {
		isNull(referProtocol, ErrorMessage.UPSUPPORTED_PROTOCOL_TYPE, () -> log.info("不支持的协议类型 param:{}", referProtocol));
		Long sellUserId = Longs.tryParse(buildTransaction.getSellerUserId());
		TblAssetAccount account = this.ownerAssetForUpdate(buildTransaction.getAssetId(), sellUserId);
		AssertUtils.isNull(account, ErrorMessage.TRANSFER_OUT_USER_NOT_EXIST, () -> log.info("minus account is null"));
//		isTrue(Objects.equals(referProtocol, ReferProtocolEnum.ERC_7211)
//				&& BigDecimalUtils.isGreaterOne(buildTransaction.getAmount()), ErrorMessage.INVALID_QUANTITY);
		return accountOpertor(buildTransaction, account, TransactionSideEnum.SELL);
	}

	@Override
	public Boolean transferFrom(TblAssetTransaction transaction, ReferProtocolEnum referProtocol) {
		TblAssetTransactionRecord minus = minus(transaction, referProtocol);
		TblAssetTransactionRecord plus = plus(transaction, referProtocol);
		if (Objects.nonNull(minus) && Objects.nonNull(plus)) {
			List<TblAssetTransactionRecord> list = Lists.newArrayList(minus, plus);
			// 保存交易流水
			this.iTblAssetTransactionRecordService.saveBatch(list);
			// 保存交易订单
			this.iTblAssetTransactionService.save(transaction);
			return true;
		}
		return false;
	}

	@Override
	public Boolean accountOpertor(TblAssetAccount account, ReferProtocolEnum referProtocol, TransactionSideEnum side) {

		return Boolean.TRUE;
	}

	/**
	 * 限制from帐户必须要有，
	 * 
	 * to帐户没有进行初如化
	 * 
	 */
	@Override
	public Boolean transferFrom(TblAssetTransaction transaction, TblAssetAccount from, TblAssetAccount to, OrderTypeEnum orderType, String orderNo) {
		AssertUtils.isNull(transaction, ErrorMessage.ASSET_NOT_EXIST, () -> log.info("transferFrom transaction is null"));
		boolean sameReferProtocol = Objects.equals(from.getReferProtocol(), to.getReferProtocol());
		isFalse(sameReferProtocol, ErrorMessage.ACCOUNT_REFER_PROTOCAL_NOT_SAME, () -> log
				.info("from:{},to:{}", JSONUtil.toJsonStr(from), JSONUtil.toJsonStr(to)));
		isFalse(Objects.equals(from.getAssetId(), to.getAssetId()), ErrorMessage.ACCOUNT_ASSET_NOT_SAME, () -> log
				.info("from:{},to:{}", JSONUtil.toJsonStr(from), JSONUtil.toJsonStr(to)));
		TblAssetTransactionRecord minus = accountOpertor(transaction, from, TransactionSideEnum.SELL);
		TblAssetTransactionRecord plus = accountOpertor(transaction, to, TransactionSideEnum.BUY);
		if (Objects.nonNull(minus) && Objects.nonNull(plus)) {
			List<TblAssetTransactionRecord> list = Lists.newArrayList(minus, plus);
			this.iTblAssetTransactionRecordService.saveBatch(list);
			return true;
		}
		return false;
	}

	/**
	 * 根据多个帐户号 查询指定的用户是否拥有指定的资产 余额大于0
	 * 
	 * (non-Javadoc)
	 * 
	 * @see xyz.xtt.pay.service.ITblAssetAccountService#accounts(java.lang.Long,
	 *      java.lang.Long[])
	 */
	@Override
	public List<TblAssetAccount> accounts(Long uid, Long[] accountNo) {
		MPJLambdaWrapper<TblAssetAccount> query = JoinWrappers
				.lambda(TblAssetAccount.class)
				.eq(TblAssetAccount::getOwnerId, uid)
				.gt(TblAssetAccount::getAmount, 0)
				.in(TblAssetAccount::getAssetId, TblAssetAccount.class, in -> in
						.select(TblAssetAccount::getAssetId)
						.in(TblAssetAccount::getAccountNo, Arrays.asList(accountNo)));
		return query.list();
	}

	@Override
	public TblAssetAccount accountsAtFirst(Long uid, Long[] accountNo) {
		MPJLambdaWrapper<TblAssetAccount> query = JoinWrappers
				.lambda(TblAssetAccount.class)
				.eq(TblAssetAccount::getOwnerId, uid)
				.gt(TblAssetAccount::getAmount, 0)
				.in(TblAssetAccount::getAssetId, TblAssetAccount.class, in -> in
						.select(TblAssetAccount::getAssetId)
						.in(TblAssetAccount::getAccountNo, Arrays.asList(accountNo)));
		List<TblAssetAccount> list = query.list();
		TblAssetAccount firstCount = list.stream().sorted(Comparator.comparing(TblAssetAccount::getCreateTime)).limit(1).findAny().orElse(null);
		return firstCount;
//		return query.one();
	}

	@Override
	public Boolean updateOwner(Long accountNo, Long fromUser, Long toUser) {
		LambdaUpdateChainWrapper<TblAssetAccount> update = new LambdaUpdateChainWrapper<>(baseMapper);
		update.eq(TblAssetAccount::getReferProtocol, ReferProtocolEnum.ERC_7211.getCode());
		update.eq(TblAssetAccount::getAccountNo, accountNo);
		update.eq(TblAssetAccount::getOwnerId, fromUser);
		update.eq(TblAssetAccount::getAmount, BigDecimal.ONE);
		update.set(TblAssetAccount::getOwnerId, toUser);
		update.setIncrBy(TblAssetAccount::getVer, 1);
		return update.update();
	}

	@Override
	public Boolean updateBalance(Long accountNo, Long fromUser, BigDecimal beforeBalance, BigDecimal afterBalance) {
		LambdaUpdateChainWrapper<TblAssetAccount> update = new LambdaUpdateChainWrapper<>(baseMapper);
		update.eq(TblAssetAccount::getReferProtocol, ReferProtocolEnum.ERC_7211.getCode());
		update.eq(TblAssetAccount::getAccountNo, accountNo);
		update.eq(TblAssetAccount::getOwnerId, fromUser);
		update.eq(TblAssetAccount::getAmount, beforeBalance);
		update.set(TblAssetAccount::getAmount, afterBalance);
		update.setIncrBy(TblAssetAccount::getVer, 1);
		return update.update();
	}

	@Override
	public BigDecimal amount(Long uid, Long assetId) {
		MPJLambdaWrapper<TblAssetAccount> query = JoinWrappers
				.lambda(TblAssetAccount.class)
				.select(TblAssetAccount::getAmount)
				.eq(TblAssetAccount::getOwnerId, uid)
				.eq(TblAssetAccount::getAssetId, assetId);
		BigDecimal one = query.one(BigDecimal.class);
		if (Objects.isNull(one)) {
			return BigDecimal.ZERO;
		}
		return one;
	}

	// 调户调整
	public TblAssetTransactionRecord accountAdjust(Long transactionId, TblAssetAccount assetAccount, TransactionSideEnum side, BigDecimal amount,
			BigDecimal price, BigDecimal fees) {
		isNull(assetAccount, null);
		BigDecimal after = assetAccount.getAmount().subtract(amount);
		if (Objects.isNull(fees)) {
			fees = BigDecimal.ZERO;
		}
//		BigDecimal after = BigDecimal.ZERO;
//		if (Objects.equals(side, TransactionSideEnum.BUY)) {
//			// 加法
//			after = assetAccount.getAmount().add(buildTransaction.getAmount());
//		} else if (Objects.equals(side, TransactionSideEnum.SELL)) {
//			// 减法
//			after = assetAccount.getAmount().subtract(buildTransaction.getAmount());
//		} else {
//			AssertUtils.isTrue(true, ErrorMessage.UNKNOWN_ERROR);
//		}
		BigDecimal totalPrice = amount.multiply(price).abs();
		AssertUtils.isTrue(BigDecimal.ZERO.compareTo(after) > 0, ErrorMessage.INSUFFICIENT_BALANCE);
		return TblAssetTransactionRecord
				.builder()
				.id(IdUtil.getSnowflakeNextId())
				.side(side.code())
				.accountNo(assetAccount.getAccountNo())
				.beforeAmount(assetAccount.getAmount())
				.transactionId(transactionId)
				.totalPrice(totalPrice)
				.amount(amount)
				.fees(fees)
				.afterAmount(after)
				.createTime(LocalDateTime.now())
				.build();
	}

	TblAssetTransactionRecord accountAdjust(Long transactionId, Long accountNo, TransactionSideEnum side, BigDecimal amount, BigDecimal price,
			BigDecimal fees) {
		LambdaQueryChainWrapper<TblAssetAccount> query = new LambdaQueryChainWrapper<>(baseMapper);
		query.eq(TblAssetAccount::getAccountNo, accountNo).last(FOR_UPDATE);
		TblAssetAccount account = query.one();
		return accountAdjust(transactionId, account, side, amount, price, fees);
	}

	TblAssetTransactionRecord accountAdjust(Long transactionId, Long assetId, Long ownerId, TransactionSideEnum side, BigDecimal amount, BigDecimal price,
			BigDecimal fees) {
		LambdaQueryChainWrapper<TblAssetAccount> query = new LambdaQueryChainWrapper<>(baseMapper);
		query.eq(TblAssetAccount::getOwnerId, ownerId).eq(TblAssetAccount::getAssetId, assetId).last(FOR_UPDATE);
		TblAssetAccount account = query.one();
		return accountAdjust(transactionId, account, side, amount, price, fees);
	}

	public Boolean transferFrom(Long transactionId, Long fromAccountNo, Long toAccountNo, OrderTypeEnum orderType, BigDecimal amount, BigDecimal price,
			BigDecimal fees) {
		TblAssetTransactionRecord minus = accountAdjust(transactionId, fromAccountNo, TransactionSideEnum.SELL, amount, price, fees);
		TblAssetTransactionRecord plus = accountAdjust(transactionId, toAccountNo, TransactionSideEnum.BUY, amount.multiply(new BigDecimal("-1")), price, fees);
		if (Objects.nonNull(minus) && Objects.nonNull(plus)) {
			List<TblAssetTransactionRecord> list = Lists.newArrayList(minus, plus);
			this.iTblAssetTransactionRecordService.saveBatch(list);
			return true;
		}
		return false;
	}

	public Boolean transferFrom(Long transactionId, Long assetId, Long fromUser, Long toUser, OrderTypeEnum orderType, BigDecimal amount, BigDecimal price,
			BigDecimal fees) {
		TblAssetTransactionRecord minus = accountAdjust(transactionId, assetId, fromUser, TransactionSideEnum.SELL, amount, price, fees);
		TblAssetTransactionRecord plus = accountAdjust(transactionId, assetId, toUser, TransactionSideEnum.BUY, amount
				.multiply(new BigDecimal("-1")), price, fees);
		if (Objects.nonNull(minus) && Objects.nonNull(plus)) {
			List<TblAssetTransactionRecord> list = Lists.newArrayList(minus, plus);
			this.iTblAssetTransactionRecordService.saveBatch(list);
			return true;
		}
		return false;
	}

	@Override
	public List<TblAssetAccount> infoWithAssetIds(Set<Long> assetId) {
		if (CollectionUtil.isEmpty(assetId)) {
			return Lists.newArrayList();
		}
		LambdaQueryChainWrapper<TblAssetAccount> query = new LambdaQueryChainWrapper<>(baseMapper);
		return query.in(TblAssetAccount::getAssetId, assetId).list();
	}

	/**
	 * 判断是否已经拥有365礼盒
	 *
	 * @param appUserId
	 * @return
	 */
	@Override
	public boolean hasGift365(Long appUserId) {
		BigDecimal amount = amount(appUserId, everydayAssetId);
		return BigDecimalUtils.isGreater(amount);
	}

	@Override
	public AssetAccountResponse accountInfoWithId(Long accountId) {
		MPJLambdaWrapper<TblAssetAccount> query = JoinWrappers.lambda(TblAssetAccount.class).eq(TblAssetAccount::getId, accountId);
		AssetAccountResponse one = query.one(AssetAccountResponse.class);
		return one;
	}

	@Override
	public Boolean putOnc2cV2(OperateUpRequest operateUpRequest, Long userId) {
		// 上架 account 数据
		LambdaUpdateChainWrapper<TblAssetAccount> updateChainWrapper = new LambdaUpdateChainWrapper<>(baseMapper);
		boolean result = updateChainWrapper
				.eq(TblAssetAccount::getAssetId, operateUpRequest.getAssetId())
				.eq(TblAssetAccount::getOwnerId, userId)
				.set(TblAssetAccount::getLastPutOnSaleDatetime, System.currentTimeMillis())
				.set(TblAssetAccount::getPrice, operateUpRequest.getPrice())
				.set(TblAssetAccount::getGuidePrice, operateUpRequest.getGuidePirce())
				.set(TblAssetAccount::getSellPattern, SellPatternEnum.BUY_NOW_PRICE.code())
				.setSql("sell_amount=amount")
				.update();
		isFalse(result, ErrorMessage.ASSET_SETTING_EX);
		// 上架 assetNo 数据
		iTblAssetNoService.on(operateUpRequest.getAssetId(), userId);
		return true;
	}

	@Override
	public Boolean putOff(Long assetId, Long userId) {
		// 修改 assetAccount
		boolean update = new LambdaUpdateChainWrapper<>(baseMapper)
				.eq(TblAssetAccount::getAssetId, assetId)
				.eq(TblAssetAccount::getOwnerId, userId)
				.set(TblAssetAccount::getSellPattern, SellPatternEnum.NORMAL.code())
				.set(TblAssetAccount::getSellAmount, BigDecimal.ZERO)
				.update();
		isFalse(update, ErrorMessage.ASSET_SETTING_EX);
		// 修改 assetNo
		iTblAssetNoService.off(assetId, userId);
		return Boolean.TRUE;
	}

	@Override
	public Long queryAccountId(Long assetId, String ownerId) {
		LambdaQueryWrapper<TblAssetAccount> query = new LambdaQueryWrapper<>();
		query.eq(TblAssetAccount::getAssetId, assetId).eq(TblAssetAccount::getOwnerId, ownerId);
		List<TblAssetAccount> tblAssetAccounts = baseMapper.selectList(query);
		if (CollectionUtil.isEmpty(tblAssetAccounts)) {
			return null;
		}
		return tblAssetAccounts.get(0).getId();
	}

}
